/*******************************************************************************
* Project: QSAR(Cute Software Architecture) 
*
* Copyright: Copyright(C) 2024 by YuetingBen, All Rights Reserved
*
* File name: Com.c
*
* Brief: ;
*
* Author: Yueting.Ben
*
* Module: Com
*
*******************************************************************************/

/** HEADER FILES **/
#include "Com.h"


/** MACRO DEFINITION **/


/** TYPEDEF DEFINITION **/
typedef struct
{
    uint16 timer;
    PduInfoType pduInfo;
    uint8 pduUpdateBit;
    uint8* signalUpdateBitPtr;
}Com_PduInfo_Type;

/** LOCAL DATA DECLARATION **/


/** GLOBAL DATA DECLARATION **/


/** LOCAL FUNCTION DECLARATION **/
static Std_ReturnType Com_FillSignalToIpduBuffer(
    PduIdType pduId
);


static Std_ReturnType Com_AssignIpduBufferToSignal(
    PduIdType pduId
);


/** GLOBAL FUNCTION DECLARATION **/
void Com_GetVersionInfo(
    Std_VersionInfoType* versionInfo
);

void Com_Init(
    const Com_ConfigType* config
);

Std_ReturnType Com_TriggerTransmit(
    PduIdType TxPduId, 
    PduInfoType* PduInfoPtr
);

void Com_RxIndication(
    PduIdType RxPduId, 
    const PduInfoType* PduInfoPtr
);

void Com_TxConfirmation(
    PduIdType TxPduId, 
    Std_ReturnType result
);

void Com_MainFunctionRx(
    void
);

void Com_MainFunctionTx(
    void
);

uint8 Com_SendSignal(
    Com_SignalIdType SignalId, 
    const void* SignalDataPtr
);

uint8 Com_ReceiveSignal(
    Com_SignalIdType SignalId, 
    void* SignalDataPtr
);


/** LOCAL DATA **/
static Com_PduInfo_Type ComTxPduInfo[ComConf_ComTxPduCfg_Pdu_Max];
static Com_PduInfo_Type ComRxPduInfo[ComConf_ComRxPduCfg_Pdu_Max];


/** GLOBAL DATA **/


/** LOCAL FUNCTION **/

/*******************************************************************************
* -Name            Com_FillSignalToIpduBuffer
* -Brief           Fill signal data to specific PDU buffer
* -Details         None
* -Param[in]       pduId: ID of the PDU that is requested to be transmitted
*
* -Return          None          
*******************************************************************************/
static Std_ReturnType Com_FillSignalToIpduBuffer(
    PduIdType pduId
)
{
    uint8 signalId;
    uint8 signalMask;
    uint8 i;
    uint8 j;
    uint8 sizeTemp;
    uint8 byteStartBitPosTemp;
    uint16 signalValueTemp;
    
    Com_SignalConfigType* signalCfgPtr;
    uint8* iPduPtr;
    
    
    for(signalId = 0u; signalId < Com_TxPduConfig[pduId].signalNumber; signalId++)
    {
        signalCfgPtr = (Com_SignalConfigType*)(&Com_TxPduConfig[pduId].signalPtr[signalId]);

        for(i = 0u; (8u * i) < (signalCfgPtr->bitSize + (signalCfgPtr->bitPosition % 8u)); i++)
        {
            /* Point to the Tx Pdu address */
            iPduPtr = Com_TxPduConfig[pduId].pduPtr;
            iPduPtr +=   (signalCfgPtr->bitPosition / 8u);

            if(COM_SIGNAL_LITTLE_ENDIAN == signalCfgPtr->signalEndianness)
            {
                iPduPtr = iPduPtr + i;
            }
            else if(COM_SIGNAL_BIG_ENDIAN == signalCfgPtr->signalEndianness)
            {
                iPduPtr = iPduPtr - i;
            }
            else
            {
                /* Do nothing */
            }

            /* Calculate the start bit position in filling specific TX PDU byte */
            if(0u == i)
            {
                byteStartBitPosTemp = signalCfgPtr->bitPosition % 8u;
            }
            else
            {
                byteStartBitPosTemp = 0u;
            }
            
            /* Calculate the data length in specific TX PDU byte, the first byte start bit position is PDU length(8u) - start position, 
            the following byte start bit position shall be 0 */
            if((signalCfgPtr->bitSize + (signalCfgPtr->bitPosition % 8u)) < (8u * (i + 1u)))
            {
                sizeTemp = signalCfgPtr->bitSize + (signalCfgPtr->bitPosition % 8u) - (8u * i);
            }
            else
            {
                sizeTemp = 8u - byteStartBitPosTemp;
            }
            
            /* Calculate the mask for clearing and filling bit in specific TX PDU byte */
            signalMask = 0x00u;
            for(j = 0u; j < sizeTemp; j++)
            {
                signalMask = signalMask << 1u ;
                signalMask |= 0x01;
            }

            if(i > 0u)
            {
                signalValueTemp = (uint16)(signalCfgPtr->signalBufferPtr[i - 1]) + (uint16)(signalCfgPtr->signalBufferPtr[i]  << 8);
                signalValueTemp = (signalValueTemp >> (8u - (signalCfgPtr->bitPosition % 8u))) & (uint16)signalMask;
            }
            else
            {
                signalValueTemp = (uint16)signalCfgPtr->signalBufferPtr[i];
                signalValueTemp = signalValueTemp & (uint16)signalMask;
            }
            
            signalMask = signalMask << byteStartBitPosTemp;
            signalValueTemp = signalValueTemp << byteStartBitPosTemp;
            signalMask = ~signalMask;
            
            *iPduPtr &= (uint8)signalMask;
            *iPduPtr |= (uint8)signalValueTemp;
        }
    }
}


/*******************************************************************************
* -Name            Com_AssignIpduBufferToSignal
* -Brief           Read signal data from specific PDU buffer
* -Details         None
* -Param[in]       pduId: ID of the PDU that is requested to be transmitted
*
* -Return          None          
*******************************************************************************/
static Std_ReturnType Com_AssignIpduBufferToSignal(
    PduIdType pduId
)
{
    uint8 signalId;
    uint8 signalMask;
    uint8 i;
    uint8 j;
    uint8 sizeTemp;
    uint8 byteStartBitPosTemp;
    uint16 signalValueTemp;
    
    Com_SignalConfigType* signalCfgPtr;
    uint8* iPduPtr;

    
    for(signalId = 0u; signalId < Com_RxPduConfig[pduId].signalNumber; signalId++)
    {
        signalCfgPtr = (Com_SignalConfigType*)(&Com_RxPduConfig[pduId].signalPtr[signalId]);

        for(i = 0u; (8u * i) < (signalCfgPtr->bitSize + (signalCfgPtr->bitPosition % 8u)); i++)
        {
            /* Point to the Tx Pdu address */
            iPduPtr = Com_RxPduConfig[pduId].pduPtr;
            iPduPtr +=   (signalCfgPtr->bitPosition / 8u);

            if(COM_SIGNAL_LITTLE_ENDIAN == signalCfgPtr->signalEndianness)
            {
                iPduPtr = iPduPtr + i;
            }
            else if(COM_SIGNAL_BIG_ENDIAN == signalCfgPtr->signalEndianness)
            {
                iPduPtr = iPduPtr - i;
            }
            else
            {
                /* Do nothing */
            }

            /* Calculate the start bit position in filling specific TX PDU byte */
            if(0u == i)
            {
                byteStartBitPosTemp = signalCfgPtr->bitPosition % 8u;
            }
            else
            {
                byteStartBitPosTemp = 0u;
            }
            
            /* Calculate the data length in specific TX PDU byte, the first byte start bit position is PDU length(8u) - start position, 
            the following byte start bit position shall be 0 */
            if((signalCfgPtr->bitSize + (signalCfgPtr->bitPosition % 8u)) < (8u * (i + 1u)))
            {
                sizeTemp = signalCfgPtr->bitSize + (signalCfgPtr->bitPosition % 8u) - (8u * i);
            }
            else
            {
                sizeTemp = 8u - byteStartBitPosTemp;
            }
            
            /* Calculate the mask for clearing and filling bit in specific TX PDU byte */
            signalMask = 0x00u;
            for(j = 0u; j < sizeTemp; j++)
            {
                signalMask = signalMask << 1u ;
                signalMask |= 0x01;
            }

            if(sizeTemp >= signalCfgPtr->bitSize)
            {
                signalCfgPtr->signalBufferPtr[i] = *iPduPtr >> byteStartBitPosTemp;
            }
            else
            {
                if(i > 0u)
                {
                    if(COM_SIGNAL_LITTLE_ENDIAN == signalCfgPtr->signalEndianness)
                    {
                        signalValueTemp = (*iPduPtr & signalMask) << (8u - (signalCfgPtr->bitPosition % 8u));
                        iPduPtr--;
                        signalValueTemp = signalValueTemp | (*iPduPtr >> (signalCfgPtr->bitPosition % 8u));
                        signalCfgPtr->signalBufferPtr[i] = 0x00u;
                        signalCfgPtr->signalBufferPtr[i] |= signalValueTemp >> 8u;
                        signalCfgPtr->signalBufferPtr[i - 1] = 0x00u;
                        signalCfgPtr->signalBufferPtr[i - 1] |= signalValueTemp >> byteStartBitPosTemp;
                    }
                    else if(COM_SIGNAL_BIG_ENDIAN == signalCfgPtr->signalEndianness)
                    {
                        signalValueTemp = (*iPduPtr & signalMask) << (8u - (signalCfgPtr->bitPosition % 8u));
                        iPduPtr++;
                        signalValueTemp = signalValueTemp | (*iPduPtr >> (signalCfgPtr->bitPosition % 8u));
                        signalCfgPtr->signalBufferPtr[i] = 0x00u;
                        signalCfgPtr->signalBufferPtr[i] |= signalValueTemp >> 8u;
                        signalCfgPtr->signalBufferPtr[i - 1] = 0x00u;
                        signalCfgPtr->signalBufferPtr[i - 1] |= signalValueTemp >> byteStartBitPosTemp;
                    }
                }
            }
        }
    }
}

/** GLOBAL FUNCTION **/

/*******************************************************************************
* -Name            Com_GetVersionInfo
* -Brief           Returns the version information of this module 
* -Details         None
* -Param[out]      versioninfo: Pointer to the version information of this module
* -Return          None          
*******************************************************************************/
void Com_GetVersionInfo(
    Std_VersionInfoType* versionInfo
)
{
    versionInfo->vendorID = (uint16)YSAR_VENDOR_ID;
    versionInfo->moduleID = (uint8)COM_MODULE_ID;
    versionInfo->sw_major_version = (uint8)COM_SW_MAJOR_VERSION;
    versionInfo->sw_minor_version = (uint8)COM_SW_MINOR_VERSION;
    versionInfo->sw_patch_version = (uint8)COM_SW_PATCH_VERSION;
}

/*******************************************************************************
* -Name            Com_Init
* -Brief           Returns the version information of this module 
* -Details         None
* -Param[in]       config: Pointer to the AUTOSAR COM module's configuration data
* -Return          None          
*******************************************************************************/
void Com_Init(
    const Com_ConfigType* config
)
{
    PduIdType id;
    Com_PduInfo_Type* comPduInfoPtr;
    
    for(id = 0; id < ComConf_ComRxPduCfg_Pdu_Max; id++)
    {
        //if(SET == comPduInfoPtr->pduUpdateBit)
    }
}

/*******************************************************************************
* -Name            Com_TriggerTransmit
* -Brief           Transmit PDU to lower layer
* -Details         None
* -Param[in]       TxPduId: ID of the SDU that is requested to be transmitted
* -Param[in]       PduInfoPtr: Pointer to PduInfo, Contains a pointer to a buffer (SduDataPtr) to where the 
*                              SDU data shall be copied, and the available buffer size in SduLengh
* -Return          None          
*******************************************************************************/
Std_ReturnType Com_TriggerTransmit(
    PduIdType TxPduId, 
    PduInfoType* PduInfoPtr
)
{
    
}


/*******************************************************************************
* -Name            Com_RxIndication
* -Brief           Indication of a received PDU from a lower layer communication interface module 
* -Details         None
* -Param[in]       RxPduId: ID of the received PDU
* -Param[in]       PduInfoPtr: Pointer to PduInfo
* -Return          None          
*******************************************************************************/
void Com_RxIndication(
    PduIdType RxPduId, 
    const PduInfoType* PduInfoPtr
)
{
    Com_PduInfo_Type* comPduInfoPtr;

    comPduInfoPtr = (Com_PduInfo_Type*)&ComRxPduInfo[RxPduId];
    memcpy((uint8 *)(Com_RxPduConfig[RxPduId].pduPtr), (uint8 *)(PduInfoPtr->SduDataPtr), PduInfoPtr->SduLength);
    comPduInfoPtr->pduUpdateBit = SET;
}


/*******************************************************************************
* -Name            Com_TxConfirmation
* -Brief           The lower layer communication interface module confirms the transmission of a PDU, 
*                  or the failure to transmit a PDU 
* -Details         None
* -Param[in]       RxPduId: ID of the received PDU
* -Param[in]       result: 
*                      E_OK: The PDU was transmitted. 
*                      E_NOT_OK: Transmission of the PDU failed
* -Return          None          
*******************************************************************************/
void Com_TxConfirmation(
    PduIdType TxPduId, 
    Std_ReturnType result
)
{
    
}

/*******************************************************************************
* -Name            Com_MainFunctionRx
* -Brief           This function performs the processing of the AUTOSAR COM module's receive processing 
* -Details         None
* -Return          None          
*******************************************************************************/
void Com_MainFunctionRx(
    void
)
{
    PduIdType id;
    Com_PduInfo_Type* comPduInfoPtr;
    
    for(id = 0; id < ComConf_ComRxPduCfg_Pdu_Max; id++)
    {
        comPduInfoPtr = (Com_PduInfo_Type*)&ComRxPduInfo[id];
        if(SET == comPduInfoPtr->pduUpdateBit)
        {
            Com_AssignIpduBufferToSignal(id);
        }
    }
}

/*******************************************************************************
* -Name            Com_MainFunctionTx
* -Brief           This function performs the processing of the AUTOSAR COM module's transmissi-on activities 
*                  that are not directly handled within the COM's function invoked by the users (e.g. RTE, SwCluC) 
* -Details         None
* -Return          None          
*******************************************************************************/
void Com_MainFunctionTx(
    void
)
{
    PduIdType id;
    Com_PduInfo_Type* comPduInfoPtr;
    
    for(id = 0; id < ComConf_ComTxPduCfg_Pdu_Max; id++)
    {
        comPduInfoPtr = (Com_PduInfo_Type*)(&ComTxPduInfo[id]);
        if((comPduInfoPtr->timer + 1u) < Com_TxPduConfig[id].comTxIPdu.txMode.timePeriod)
        {
            comPduInfoPtr->timer++;
        }
        else
        {
            Com_FillSignalToIpduBuffer(id);
            comPduInfoPtr->timer = 0u;
            comPduInfoPtr->pduInfo.SduDataPtr = Com_TxPduConfig[id].pduPtr;
            comPduInfoPtr->pduInfo.SduLength = 8u;
            PduR_ComTransmit(id, (PduInfoType*)(&comPduInfoPtr->pduInfo));
        }
    }
}

/*******************************************************************************
* -Name            Com_SendSignal
* -Brief           The service Com_SendSignal updates the signal object identified by SignalId with the signal 
*                  referenced by the SignalDataPtr parameter 
* -Details         None
* -Param[in]       SignalId: Id of signal to be sent
* -Param[in]       SignalDataPtr: Reference to the signal data to be transmitted 
* -Return          E_OK: service has been accepted
*                  COM_SERVICE_NOT_AVAILABLE: corresponding I-PDU group was stopped
*                  COM_BUSY: in case the TP-Buffer is locked for large data types handling
*******************************************************************************/
uint8 Com_SendSignal(
    Com_SignalIdType SignalId, 
    const void* SignalDataPtr
)
{
    uint8 i;
    uint8* dataPtr = (uint8*)SignalDataPtr;
    for(i = 0u; i < (Com_TxSignal[SignalId].bitSize / 8u) + 1u; i++)
    {
        Com_TxSignal[SignalId].signalBufferPtr[i] = dataPtr[i];
    }
}

/*******************************************************************************
* -Name            Com_ReceiveSignal
* -Brief           Com_ReceiveSignal copies the data of the signal identified by SignalId to the location specified by 
*                  SignalDataPtr 
* -Details         None
* -Param[in]       SignalId: Id of signal to be sent
* -Param[Out]      SignalDataPtr: Reference to the location where the received signal data shall be stored 
* -Return          E_OK: service has been accepted
*                  COM_SERVICE_NOT_AVAILABLE: corresponding I-PDU group was stopped
*                  COM_BUSY: in case the TP-Buffer is locked for large data types handling
*******************************************************************************/
uint8 Com_ReceiveSignal(
    Com_SignalIdType SignalId, 
    void* SignalDataPtr
)
{
    uint8 i;
    uint8* dataPtr = (uint8*)SignalDataPtr;
    for(i = 0u; i < (Com_RxSignal[SignalId].bitSize / 8u) + 1u; i++)
    {
        dataPtr[i] = Com_RxSignal[SignalId].signalBufferPtr[i];
    }

}


